package cn.autumnorange.app.common.consumerproducer.util;

import cn.autumnorange.app.common.dto.ResultDto;
import cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationUtil {

    /**
     * 类,相关接口指定的方法是否有该指定的注解
     *
     * @param className
     * @param methodName
     * @return
     */

    public ResponseEntity<ResultDto<Annotation>> getAnnotation(@PathVariable(value = "className") String className, @PathVariable(value = "methodName") String methodName, @PathVariable(value = "annotationName") String annotationName) throws ClassNotFoundException {
        Annotation checkAnnotation=checkAnnotation(className, methodName, annotationName, true, true);
//       boolean checkAnnotation= checkAnnotation("cn.autumnorange.app.util.consumer.controller.RPCIdempotentLockTargetCheckTest3", "testvoid", "cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget", true, true);
        return  ResponseEntity.ok().body(ResultDto.createDataResult(checkAnnotation));
    }

    public static void main(String[] args) throws ClassNotFoundException {

        Method[] methods = AnnotationUtil.class.getMethods();


//        boolean hascheckAnnotation = checkAnnotation("cn.autumnorange.app.util.consumer.controller.UtilController", "timestampToYYMMDDlongorg.springframework.http.ResponseEntity", "cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget", true, true);
//        boolean hascheckAnnotation = checkAnnotation("cn.autumnorange.app.util.consumer.controller.RPCIdempotentLockTargetCheckTest1", "testvoid", "cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget", true, true);
//        boolean hascheckAnnotation = checkAnnotation("cn.autumnorange.app.util.consumer.controller.RPCIdempotentLockTargetCheckTest2", "testvoid", "cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget", true, true);
        Annotation annotation=checkAnnotation("cn.autumnorange.app.util.consumer.controller.RPCIdempotentLockTargetCheckTest3", "testvoid", "cn.autumnorange.app.common.rpc.lock.RPCIdempotentLockTarget", true, true);

//cn.autumnorange.app.util.consumer.controller.RPCIdempotentLockTargetCheckTest1
        System.out.println(annotation);
    }

    /**
     * @param classesName
     * @param methodName
     * @param annotationName
     * @return
     */
    public static Annotation checkAnnotation(String classesName, String methodName, String annotationName, boolean checkInterface, boolean checkParent) throws ClassNotFoundException {
        Annotation rpcIdempotentLockTarget =null;
        if (StringUtils.trimToEmpty(classesName).equals("")) {
            return null;
        }
        Method[] methods = null;
        Class  classes = Class.forName(classesName);

        methods = classes.getMethods();
        if (methods != null) {
            for (Method method : methods) {
                //匹配注解方法是否存在指定的类方法中 匹配方式 方法名+方法参数+方法返回参数 组成字符串匹配
                String methodMsg = getMethodAllMSG(method);
//                timestampToYYMMDDlongorg.springframework.http.ResponseEntity
                if (methodMsg.equals(methodName)) {
//          rpcIdempotentLockTarget
                    Class annotationClass  = Class.forName(annotationName);

                    rpcIdempotentLockTarget =
                            method.getAnnotation(annotationClass);
                    if (rpcIdempotentLockTarget instanceof RPCIdempotentLockTarget) {
//                            result = ((RPCIdempotentLockTarget) rpcIdempotentLockTarget).rpcLock();
                        return rpcIdempotentLockTarget;
                    }
                }
            }
        }
        if (checkInterface) {
            Class<?>[] interfaces = classes.getInterfaces();
            for (Class classInterface : interfaces) {
                rpcIdempotentLockTarget = checkAnnotation(classInterface.getName(), methodName, annotationName, checkInterface, checkParent);
                if (rpcIdempotentLockTarget!=null ) {
                    return rpcIdempotentLockTarget;
                }
            }
        }
        if (checkParent) {
            Class<?> superclass = classes.getSuperclass();
            if(superclass!=null){
                rpcIdempotentLockTarget = checkAnnotation(superclass.getName(), methodName, annotationName, checkInterface, checkParent);
                if (rpcIdempotentLockTarget!=null ) {
                    return rpcIdempotentLockTarget;
                }
            }
        }
        return rpcIdempotentLockTarget;
    }

    public static String getMethodAllMSG(Method method) {
        if (method == null) {
            return null;
        }
        String methodMsg = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        String paramTypeClassStr = "";
        for (Class<?> paramTypeClass : parameterTypes) {
            paramTypeClassStr += paramTypeClass.getName();
        }
        methodMsg += paramTypeClassStr;
        Class<?> returnTYpes = method.getReturnType();
        methodMsg += returnTYpes.getName();

        return methodMsg;
    }

    public static boolean existsAnnotation(Class<?> cs, Class<? extends Annotation> annotation) {
        boolean rs = cs.isAnnotationPresent(annotation);
        if (!rs) {
            rs = cs.getSuperclass() != null && existsAnnotation(cs.getSuperclass(), annotation);
        }
        if (!rs) {
            Class<?>[] interfaces = cs.getInterfaces();
            for (Class<?> f : interfaces) {
                rs = existsAnnotation(f, annotation);
                if (rs) {
                    break;
                }
            }
        }
        if (!rs) {
            Annotation[] annotations = cs.getAnnotations();
            for (Annotation an : annotations) {
                //        用native关键字描述，说明是一个底层方法，实际上是使用c/c++实现的，java里面没有实现，那么这个方法是干什么的呢？我们从上面的注释可以解读：
                //
                // 如果是A.isAssignableFrom(B)
                // 确定一个类(B)是不是继承来自于另一个父类(A)，一个接口(A)是不是实现了另外一个接口(B)，或者两个类相同。主要，这里比较的维度不是实例对象，而是类本身，因为这个方法本身就是Class类的方法，判断的肯定是和类信息相关的。
                //
                // 也就是判断当前的Class对象所表示的类，是不是参数中传递的Class对象所表示的类的父类，超接口，或者是相同的类型。是则返回true，否则返回false。
                rs = annotation.isAssignableFrom(an.getClass());
                if (rs) {
                    break;
                }
            }
        }
        return rs;
    }
}
